package cn.sinjet.communication.bluetooth;

import java.lang.reflect.Method;
import java.util.Set;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.util.Log;
import cn.sinjet.communication.bluetooth.SppBluetoothChatService.OnChatServiceListener;

public class SppBluetooth implements OnChatServiceListener{
	private final static String tag = "SPP";//ThreeBtCtrl.class.getSimpleName();
	public Context mContext = null;
	// Key names received from the BluetoothChatService Handler
	private BluetoothAdapter mBluetoothAdapter = null;
	// Member object for the chat services
	public SppBluetoothChatService mChatService = null;
	private BluetoothDevice mBluetoothDevice = null;
	
	private boolean mIsToureFound = false;
	private int mConnectStatus = BTState.DISCONNECTED;
	private static final int BT_CONNECT_TIMEOUT = 30000;
	private boolean mIsConnecttingPeriod = false;
//	private static SppBluetooth mSPPBluetooth = null;
	private Handler mHandler = null; 
	public SppBluetooth(Context context){
		mContext = context;
	}
	/*public synchronized static SppBluetooth getInstance(Context context){
		if(mSPPBluetooth == null)
			mSPPBluetooth = new SppBluetooth(context);
		return mSPPBluetooth;
	}*/
	
	Handler m_appInitOkHandler = new Handler();

	@SuppressLint("NewApi")
	public boolean initSppBluetooth() {
		registerReceiver();
		if(mBluetoothAdapter == null)
		   mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
	// If the adapter is null, then Bluetooth is not supported
       if (mBluetoothAdapter == null) return false;
	// If BT is not on, request that it be enabled.
	// setupChat() will then be called during onActivityResult
		if (!mBluetoothAdapter.isEnabled()) {
			mBluetoothAdapter.enable();
		}
	
		if (mChatService == null)
			setupChat();
			return true;
		}
	
	private void registerReceiver(){
    	// Register for broadcasts when a device is discovered
			IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
			mContext.registerReceiver(mReceiver,filter);

			// Register for broadcasts when discovery has finished
			filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
			mContext.registerReceiver(mReceiver,filter);    			
    }
	
	public interface SppBluetoothCallback{
		void onBTStateChange(int state);
		void onReceived(byte[] buf,int len);
	}
	
	private SppBluetoothCallback mSppBluetoothCallback = null;
	public void setSppBluetoothCallback(SppBluetoothCallback sppBluetoothCallback){
		mSppBluetoothCallback = sppBluetoothCallback;
	}

	
    private void onBTStateChange(int state){
    	 Log.d(tag,"onBTStateChange: "+mConnectStatus +"->"+state);
    	 if(mConnectStatus == state)
    		 return;
    	 if(mSppBluetoothCallback != null)
    		 mSppBluetoothCallback.onBTStateChange(state);
    	 mConnectStatus = state;
    	 
    	 if(mConnectStatus == BTState.CONNECTED){
 			mIsConnecttingPeriod = false;
 			mHandler.removeCallbacks(mConnectTimeoutRunnable);
 		}
    }
    
    
	public void deInitThreeBt() {
		// Make sure we're not doing discovery anymore
		if (mBluetoothAdapter != null) {
			mBluetoothAdapter.cancelDiscovery();
		}

		if (mChatService != null)
			mChatService.stop();
	}

	private void setupChat() {
		Log.d(tag, "setupChat()");
		// Initialize the BluetoothChatService to perform bluetooth connections
		mChatService = new SppBluetoothChatService();
		mChatService.setOnChatServiceListener(this);
	}

	// The BroadcastReceiver that listens for discovered devices and
	// changes the title when discovery is finished
	private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			// When discovery finds a device
			if (BluetoothDevice.ACTION_FOUND.equals(action)) {
				// Get the BluetoothDevice object from the Intent
				BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
				if(device == null)
					return;
				Log.d(tag,"device found: name = "+ device.getName() + " addr = "+ device.getAddress());
				String strDeviceName = device.getName();
				if (  (strDeviceName != null&& strDeviceName.equals(BluetoothModel.BT_NAME1))
						||(strDeviceName != null&& strDeviceName.equals(BluetoothModel.BT_NAME2))
						|| (device.getAddress() != null && device.getAddress().equals("00:18:66:66:00:DA"))
					){
					mIsToureFound = true;
					devInSearchResult(device);
				}
			} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
				Log.d(tag,"device discovery finished");
				if (!mIsToureFound && mConnectStatus == BTState.SCANING) {
					 onBTStateChange(BTState.NOT_FOUND);
				}
				if(!mIsToureFound && mIsConnecttingPeriod){//device not found and it is not timeout
					searchBT();//try search again
				}
			}
		}
	};
	

	
	
	private void devInSearchResult(BluetoothDevice deviceResult){
		/*Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
		//no paired devices,it is new 
		if(pairedDevices != null && pairedDevices.size()>0){
			for (BluetoothDevice device : pairedDevices) {
				//Log.d(tag,"pairedDevice : name = "+ device.getName() + " addr = "+ device.getAddress());
				if (null != device.getName()&& device.getName().equals(BluetoothModel.BT_NAME)) {
					if(!device.getAddress().equals(deviceResult.getAddress())){
					      unpairDevice(device);
					      break;
			         }
				}
		   }
	    }*/
		mBluetoothDevice = deviceResult;
		connectDevice(deviceResult, true,true);
    }
	
	/*
	 * function: connect a bt device
	 * isNewFound:    if it is the result in discovery result or connect directly
	 * 
	 */
	
private void unpairDevice(BluetoothDevice device) {
		Log.d(tag,"unpairDevice : name = "+ device.getName() + " addr = "+ device.getAddress());		
		try {
		    Method m = device.getClass().getMethod("removeBond", (Class[]) null);
		    m.invoke(device, (Object[]) null);
		} catch (Exception e) {
		    Log.e("unpairDevice", e.getMessage());
		}
 }

	private void disconnectBT(){
		try{
			if (mBluetoothAdapter != null) {
				mBluetoothAdapter.cancelDiscovery();
			}
	
			if (mChatService != null){
				mChatService.stop();
				
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		
	}

	
	/**
	 * Request Connect to BT
	 * if my device has been paired before,connect it
	 * else do a search
	 */
	public void requestConnect(){
		if(mIsConnecttingPeriod)
			return;
		// Get local Bluetooth adapter
		 if(mBluetoothAdapter == null)
			mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		// If the adapter is null, then Bluetooth is not supported
	    if (mBluetoothAdapter == null) {
//				LogicModel.getInstance().showGreenToast("������֧��");
				return;
		}
		// If BT is not on, request that it be enabled.
		// setupChat() will then be called during onActivityResult
		if (!mBluetoothAdapter.isEnabled()) {
			mBluetoothAdapter.enable();
			//return;
		}
		
		if (mChatService == null)
			setupChat();

		
		if (mBluetoothAdapter.isDiscovering()) {
			mBluetoothAdapter.cancelDiscovery();
		}
		
		startConnectTimeoutHandler();
		
		// Get a set of currently paired devices
		Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
		if(pairedDevices == null ||pairedDevices.size()<=0){
			Log.d(tag,"no paired devices");
			searchBT();//not paired,search
			return;
		}
		boolean isMyDevicePaired = false;
		for (BluetoothDevice device : pairedDevices) {
			Log.d(tag,"pairedDevice : name = "+ device.getName() + " addr = "+ device.getAddress());
			if (  (null != device.getName()&& device.getName().equals(BluetoothModel.BT_NAME1))
				|| (null != device.getName()&& device.getName().equals(BluetoothModel.BT_NAME2))
				) {
				mBluetoothDevice = device;
	            isMyDevicePaired = true;   //paired,connect it
	            connectDevice(device,false,true);
	            return;
			}
		}
		if(!isMyDevicePaired){
			Log.d(tag,"no mydevices paired");
			searchBT();//not paired search
		}
	}
	
	
	
	private void startConnectTimeoutHandler(){
		mIsConnecttingPeriod = true;
		
		if(mHandler == null)
			mHandler = new Handler();
//		mHandler.removeCallbacks(mConnectTimeoutRunnable);
		mHandler.postDelayed(mConnectTimeoutRunnable, BT_CONNECT_TIMEOUT);
	}
	
	Runnable mConnectTimeoutRunnable = new Runnable() {
		@Override
		public void run() {
			// TODO Auto-generated method stub
			mIsConnecttingPeriod = false;
			if(!isConnected())
				BluetoothModel.getInstance().clearBTMode();
//			clearBT();
		}
	};
	
	/*
	 if (m_nConnectStatus == LogicModel.BT_DISCONNECT
				|| m_nConnectStatus == LogicModel.BT_DO_NOT_FOUND) {

			Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
					.getBondedDevices();
			if (pairedDevices.size() > 0) {

				for (BluetoothDevice device : pairedDevices) {
					if (null != device.getName()&& device.getName().equals(LogicModel.DEFAULT_DEVICE_NAME)) {
						connectTlDevice(device,false);

						Log.d("BluetoothChatService","clickConnect connect to: name = "+ device.getName() + " addr = "+ device.getAddress());
						break;
					}
				}
			} else {
				if (!mBluetoothAdapter.isDiscovering()) {
					mBluetoothAdapter.startDiscovery();
				}
			}
	 */
	private void connectDevice(BluetoothDevice device, boolean isSearchResult,boolean secure) {
		if(device == null)
			return;
		mIsToureFound = true;
		
		if (mBluetoothAdapter == null) {
			return;
		}
		String strDeviceAddr = device.getAddress();
        if(strDeviceAddr == null)  return;
        	
        if (mBluetoothAdapter.isDiscovering()) {
			mBluetoothAdapter.cancelDiscovery();
		}
		
		// Get the BluetoothDevice object
		//BluetoothDevice device = mBluetoothAdapter
		//		.getRemoteDevice(strDeviceAddr);
		// Attempt to connect to the device
        Log.d(tag, "Trying a connection with BTTTTTTTTTTTTTT addr:"+device.getAddress());
		mChatService.connect(device, isSearchResult,secure);
	}


	/**
	 * Sends a message.
	 * 
	 * @param message
	 *            A string of text to send.
	 */
	/*private void sendMessage(String message) {
		// Check that we're actually connected before trying anything
		if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
			// EnvCenter.showGreenToast("δ����");
			return;
		}

		// Check that there's actually something to send
		if (message.length() > 0) {
			// Get the message bytes and tell the BluetoothChatService to write
			byte[] send = message.getBytes();
			mChatService.write(send);
		}
	}*/

	public void sendMessage(byte[] send) {
		// Check that we're actually connected before trying anything
		if(mChatService == null)
			return;
		
		if (mChatService.getState() != BTState.CONNECTED) {
			Log.d(tag,"send message but bt not connected");
			return;
		}

		// Check that there's actually something to send
		if (send.length > 0) {
			// Get the message bytes and tell the BluetoothChatService to write
			mChatService.write(send);
		}
	}

	public void setToMcu(byte[] p, int len) {

		byte[] szMsg = new byte[len + 5];
		szMsg[0] = (byte) 0xFF;
		szMsg[1] = (byte) 0x55;
		szMsg[2] = (byte) (len + 1);
		szMsg[3] = (byte) 0x03;
		System.arraycopy(p, 0, szMsg, 4, len);

		byte sum = 0;
		int s = 0;
		int i = 0;
		for (i = 2; i < len + 4; i++) {
			s += (szMsg[i] & 0xFF);
		}
		sum = (byte) (s & 0xFF);
		szMsg[len + 4] = sum;

		sendMessage(szMsg);
	}

	public void searchBT() {
		if (mBluetoothAdapter == null) {
			return;
		}
		if (mBluetoothAdapter.isDiscovering()) {
			mBluetoothAdapter.cancelDiscovery();
		}
		// Request discover from BluetoothAdapter
		mIsToureFound = false;
		mBluetoothAdapter.startDiscovery();
		onBTStateChange(BTState.SCANING);
	}

	public boolean isConnected() {
		// TODO Auto-generated method stub
		boolean ret = (mConnectStatus == BTState.CONNECTED)?true:false;
		return ret;
	}
	public void requestDisconnect() {
		// TODO Auto-generated method stub
		disconnectBT();
	}
	public void clearBT() {
		// TODO Auto-generated method stub
		if (mBluetoothAdapter != null) {
			mBluetoothAdapter.cancelDiscovery();
		}
		if (mChatService != null)
			mChatService.stop();
	}
	@Override
	public void onStateChange(int state,int flag) {
		// TODO Auto-generated method stub
		onBTStateChange(state);
		if(state == BTState.DISCONNECTED){
			if(mIsConnecttingPeriod){
				try{
					Thread.sleep(1500);//sleep a little bit then try again
				}catch(Exception e){
					e.printStackTrace();
				}
	 		   if(flag == ErrFlag.CONNECT_FAIL_WITHOUT_SEARCH && mIsConnecttingPeriod)
	 			  connectDevice(mBluetoothDevice, false, true);
	 		   else if(flag == ErrFlag.CONNECT_FAIL_WITH_SEARCH && mIsConnecttingPeriod){//try to reconnect 
	 			   connectDevice(mBluetoothDevice, true, true);
	 		   }	
		   }
	    }
	}
	@Override
	public void onReceived(byte[] buf, int len) {
		// TODO Auto-generated method stub
		if(mSppBluetoothCallback != null)
			mSppBluetoothCallback.onReceived(buf, len);
	}

	public void tryToKeepConnected() {
		// TODO Auto-generated method stub
		if(!isConnected() && !mIsConnecttingPeriod)//not connected and not trying 
			requestConnect();//try to connect
	}
}
